﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using TSU.FAMC.ComputerEngineering.Classes.BooleanMaths.Functions.Readers;
using TSU.FAMC.ComputerEngineering.Classes.BooleanMaths.Functions;
using TSU.FAMC.ComputerEngineering.Classes.Circuits;
using TSU.FAMC.ComputerEngineering.Classes.Circuits.Readers;
using TSU.FAMC.ComputerEngineering.Classes.Diagnostics.PathDelayFaults;
using TSU.FAMC.ComputerEngineering.Classes.BooleanMaths.Fundamental;
using TSU.FAMC.ComputerEngineering.Classes.Enums;

namespace PDFBuilder
{
    public partial class PDFBuilderForm : Form
    {
        public PDFBuilderForm()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            if (openFileDlg.ShowDialog() != DialogResult.OK)
            {
                return;
            }

            if (openFileDlg.FileNames.Length == 0)
            {
                MessageBox.Show("Не выбрано ни одного файла системы для построения тестов!");
                return;
            }

            // reading files
            reportBox.Clear();
            var errorsCounter = 0;
            var tests = new List<PdfAnalyzer>();
            var successCircuitsFiles = new List<String>();
            var sucessCircuits = new List<Circuit>();
            foreach (var fileName in openFileDlg.FileNames)
            {
                var fileStr = String.Empty;

                try
                {
                    // reading file
                    var streamReader = new StreamReader(fileName);
                    fileStr = streamReader.ReadToEnd();
                }
                catch (Exception ex)
                {
                    reportBox.Text += string.Format("{0}.\r\n Ошибка: не удалось прочитать файл. Подрбнее: {1} \r\n\r\n", fileName, ex.Message);
                    errorsCounter++;
                    continue;
                }

                // reading circuit

                var reader = new CircuitReaderPlain();
                reader.Input = fileStr;

                try
                {
                    reader.Read();
                }
                catch (Exception ex)
                {
                    reportBox.Text += string.Format("{0}.\r\n Ошибка: не удалось прочитать схему. Подрбнее: {1} \r\n\r\n", fileName, ex.Message);
                    errorsCounter++;
                    continue;
                }

                // building tests
                var robustTests = new List<PdfTest>();
                var nonRobustTests = new List<PdfTest>();
                var nonRobustRelativelyRobustTests = new List<PdfTest>();
                try
                {
                    var analyzer = new PdfAnalyzer();
                    analyzer.BuildTest(reader.Circuit);

                    // saving test
                    tests.Add(analyzer);

                    robustTests = analyzer.RobustTest;
                    nonRobustTests = analyzer.NonRobustTest;
                    nonRobustRelativelyRobustTests = analyzer.NonRobustRelativelyRobusTest;
                }
                catch (Exception ex)
                {
                    reportBox.Text += string.Format("{0}.\r\n Ошибка: не удалось построить тесты для системы. Подрбнее: {1} \r\n\r\n", fileName, ex.Message);
                    errorsCounter++;
                    continue;
                }

                // saving success circuit
                sucessCircuits.Add(reader.Circuit);

                // saving success file name
                successCircuitsFiles.Add(fileName);

                reportBox.Text += string.Format("{0}.\r\n Успех: тесты построены ({1}). Paths: {2}, robust: {3}, relativly robust: {4}, non-robust: {5}. \r\n\r\n", fileName, reader.Circuit.CountPaths(), robustTests.Count + nonRobustRelativelyRobustTests.Count + nonRobustTests.Count, robustTests.Count, nonRobustRelativelyRobustTests.Count, nonRobustTests.Count);

                if (PrintTestsCheckBox.Checked)
                {
                    foreach (var test in robustTests)
                    {
                        reportBox.Text += string.Format("Robust. номер функции: {0}, v1: {1}, v2: {2}, path: {3} \r\n", test.Data, test.V1, test.V2, test.Data2);
                    }

                    reportBox.Text += "\r\n\r\n";

                    foreach (var test in nonRobustRelativelyRobustTests)
                    {
                        reportBox.Text += string.Format("NonRobust (Relative Robust). номер функции: {0}, v1: {1}, v2: {2}, path: {3} \r\n", test.Data, test.V1, test.V2, test.Data2);
                    }

                    reportBox.Text += "\r\n\r\n";

                    foreach (var test in nonRobustTests)
                    {
                        reportBox.Text += string.Format("NonRobust. номер функции: {0}, v1: {1}, v2: {2}, path: {3} \r\n", test.Data, test.V1, test.V2, test.Data2);
                    }

                    reportBox.Text += "\r\n\r\n\r\n\r\n";
                }
            }


            if (FileOutputCheckBox.Checked)
            {
                // showing select folder dialog
                if (OutputFolderBrowserDialog.ShowDialog() == DialogResult.OK &&
                    OutputFolderBrowserDialog.SelectedPath != String.Empty)
                {
                    // output folder selected

                    // printing tests to files
                    for (var i = 0; i < successCircuitsFiles.Count; i++)
                    {
                        var outputStr = String.Empty;

                        var robustTests = new List<PdfTest>();
                        var nonRobustTests = new List<PdfTest>();
                        var nonRobustRelativelyRobustTests = new List<PdfTest>();

                        robustTests = tests[i].RobustTest;
                        nonRobustTests = tests[i].NonRobustTest;
                        nonRobustRelativelyRobustTests = tests[i].NonRobustRelativelyRobusTest;

                        // retrieving circuit object
                        var circuit = sucessCircuits[i];

                        // printing header
                        outputStr += ".type fd\r\n";
                        outputStr += ".i " + circuit.Inputs.Count + "\r\n";
                        outputStr += ".o " + circuit.Outputs.Count + "\r\n";

                        if (!RobustOutputCheckBox.Checked)
                        {
                            outputStr += ".p " + (robustTests.Count + nonRobustTests.Count + nonRobustRelativelyRobustTests.Count) * 2 + "\r\n\r\n";
                        }
                        else
                        {
                            outputStr += ".p " + robustTests.Count * 2 + "\r\n\r\n";
                        }

                        // printing robust test
                        foreach (var test in robustTests)
                        {
                            // determing function characteristic
                            var funcChar = new BooleanVector(circuit.Outputs.Count);
                            var funcNum = (int)test.Data;
                            funcChar[funcNum] = BooleanValue.True;

                            outputStr += string.Format("{0} {2}\r\n{1} {2}\r\n", test.V1, test.V2, funcChar);
                        }

                        // splitter
                        if (robustTests.Count > 0)
                        {
                            outputStr += "\r\n";
                        }

                        if (!RobustOutputCheckBox.Checked)
                        {
                            // printing non-robust tests

                            // printing relatively-robust test
                            foreach (var test in nonRobustRelativelyRobustTests)
                            {
                                // determing function characteristic
                                var funcChar = new BooleanVector(circuit.Outputs.Count);
                                var funcNum = (int)test.Data;
                                funcChar[funcNum] = BooleanValue.True;

                                outputStr += string.Format("{0} {2}\r\n{1} {2}\r\n", test.V1, test.V2, funcChar);
                            }

                            // splitter
                            if (nonRobustRelativelyRobustTests.Count > 0)
                            {
                                outputStr += "\r\n";
                            }

                            // printing non-robust test
                            foreach (var test in nonRobustTests)
                            {
                                // determing function characteristic
                                var funcChar = new BooleanVector(circuit.Outputs.Count);
                                var funcNum = (int)test.Data;
                                funcChar[funcNum] = BooleanValue.True;

                                outputStr += string.Format("{0} {2}\r\n{1} {2}\r\n", test.V1, test.V2, funcChar);
                            }

                            // splitter
                            if (nonRobustTests.Count > 0)
                            {
                                outputStr += "\r\n";
                            }
                        }


                        // printing footer
                        outputStr += ".e";


                        // writing file
                        var fileName = Path.GetFileNameWithoutExtension(successCircuitsFiles[i]) + "_pdf.test";
                        var outputFilePath = OutputFolderBrowserDialog.SelectedPath + Path.DirectorySeparatorChar + fileName;

                        try
                        {
                            var streamWriter = new StreamWriter(outputFilePath);
                            streamWriter.Write(outputStr);
                            streamWriter.Close();
                        }
                        catch (Exception ex)
                        {
                            reportBox.Text += string.Format("{0}. Ошибка: не удалось записать в файл. Подрбнее: {1} \r\n\r\n", fileName, ex.Message);
                            errorsCounter++;
                            continue;
                        }
                    }
                }
            }


            if (errorsCounter == 0)
            {
                MessageBox.Show("Построение тестов завершено!");
            }
            else
            {
                MessageBox.Show(string.Format("Во время построения тестов возникло {0} ошибок", errorsCounter));
            }
        }
    }
}
